package research.dao.hibernate;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;

import research.dao.IEntityDAO;
import research.dao.hibernate.HibernateUtil;
import research.entity.Entity;
import research.model.IHierarchyProvider;

public class HibernateDAO implements IEntityDAO {
	private Session session = null;

	public HibernateDAO() {
	}

	public void setSession(Session s) {
		this.session = s;
	}

	protected Session getSession() {
		if (session == null)
			session = HibernateUtil.getSessionFactory().getCurrentSession();
		return session;
	}

	@Override
	public Entity get(Class<?> type, long id, boolean lock) {
		Entity entity = null;

		try {
			getSession().beginTransaction();
			if (lock)
				entity = (Entity) getSession().load(type, id,
						LockMode.UPGRADE);
			else
				entity = (Entity) getSession().load(type, id);
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}

		return entity;
	}

	@Override
	public List<Entity> getAll(Class<?> type) {
		return findByCriteria(type);
	}

//	public List<?> findByExample(StorageEntity exampleInstance, String[] excludeProperty) {
//		Criteria crit = getSession().createCriteria(getPersistentClass());
//		Example example = Example.create(exampleInstance);
//		for (String exclude : excludeProperty) {
//			example.excludeProperty(exclude);
//		}
//		crit.add(example);
//		return crit.list();
//	}

	@Override
	public Entity makePersistent(Entity entity) {
		try {
			getSession().beginTransaction();
			getSession().saveOrUpdate(entity);
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}

		return entity;
	}

	@Override
	public void makeTransient(Entity entity) {
		try {
			getSession().beginTransaction();
			getSession().delete(entity);
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}
	}

	public void flush() {
		getSession().flush();
	}

	public void clear() {
		getSession().clear();
	}

	@SuppressWarnings("unchecked")
	protected List<Entity> findByCriteria(Class<?> type, Criterion... criterion) {
		List<Entity> list = null;
		try {
			getSession().beginTransaction();
			Criteria crit = getSession().createCriteria(type);
			for (Criterion c : criterion) {
				crit.add(c);
			}
			list =  (List<Entity>) crit.list();
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}

		return list;
	}
	
	@Override
	public List<Entity> getChildren(Entity entity,
			IHierarchyProvider hierarchy) {
		List<Entity> list = null;
		try {
			getSession().beginTransaction();
			Entity persist = (Entity) getSession().get(entity.getClass(), entity.getId());
			list = hierarchy.getChildren(persist);
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}

		return list;
	}

	@Override
	public Entity getParent(Entity entity,
			IHierarchyProvider hierarchy) {
		Entity res = null;

		try {
			getSession().beginTransaction();
			getSession().merge(entity);
			res = hierarchy.getParent(entity);
			getSession().getTransaction().commit();
		} catch (HibernateException e) {
			getSession().getTransaction().rollback();
			e.printStackTrace();
		}

		return res;
	}

}